/*
 * Chastoslov
 * Copyright (C) 2009 Alexandr Stroghov
 * 
 * stroghov@gmail.com
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms of the 
 * GNU General Public License, version 2, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program; if 
 * not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 * MA 02111-1307 USA
*/
package world.ah.wf.guiclient;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.Connection;
import java.util.Iterator;
import java.util.Properties;
import java.util.SortedMap;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Insets;
import java.awt.event.WindowEvent;
import javax.swing.WindowConstants;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import javax.swing.JPanel;
import java.awt.event.ComponentEvent;

public class DialogExportMarked extends JDialog {
  private boolean inProgress = false; // Состояние процесса 
  private boolean stopProgress = false; // Прекратить процесс 
  private String exportedCountLabel = "Words exported";
  private String progressTimeLabel = "Time elapsed";
  private String progressSpeedLabel = "Speed";
  private String wordsPerSecond = "words per second";
  private String exportLabel = "Export";
  private String stopLabel = "Stop";
  //
  private Connection conn;
  public void setConn(Connection conn) {this.conn = conn;};
  private SortedMap charset = Charset.availableCharsets();
  private String lastCharset;
  //  
  private JTextField tfFileName = new JTextField();
  private JLabel labFile = new JLabel();
  private JButton bPickFile = new JButton();
  private JButton bExport = new JButton();
  private JButton bClose = new JButton();
  private JLabel labProgressCount = new JLabel();
  private JLabel labProgressTime = new JLabel();
  private JLabel labProgressSpeed = new JLabel();
  private GridBagLayout gridBagLayout1 = new GridBagLayout();
  private JPanel pFile = new JPanel();
  private JPanel pButtons = new JPanel();
  private BorderLayout borderLayout1 = new BorderLayout();
  private GridBagLayout gridBagLayout2 = new GridBagLayout();
  private JPanel pCompensator = new JPanel();
  private JLabel labCharset = new JLabel();
  private JComboBox combCharset = new JComboBox();

  //
  public DialogExportMarked() {this(null, "", false);}
  public DialogExportMarked(Frame parent, String title, boolean modal) {
    super(parent, title, modal);
    try {jbInit();} catch(Exception e) {e.printStackTrace();}
    //
    General.centerFrame(this);
    // 
    labProgressCount.setText(" ");
    labProgressTime.setText(" ");
    labProgressSpeed.setText(" ");
    // Load the dialog properties 
    Properties prop = new Properties();
    try {
      prop.load(new FileInputStream("wfDialogExportMarked.properties"));
      tfFileName.setText(prop.getProperty("LastFileName", ""));
      lastCharset = prop.getProperty("LastCharset", "");
    } catch(Exception ex) {ErrorShower.show(null, "loading the dialog properties", "", ex);}
    //
    // Язык (не предполагается переустановка языка во время работы с формой)
    setLang();
    //
  }

  private void jbInit() throws Exception {
    this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    this.setSize(new Dimension(400, 349));
    this.getContentPane().setLayout(gridBagLayout1);
    this.setTitle("Export checked words");
    this.setResizable(false);
    this.addComponentListener(new java.awt.event.ComponentAdapter()
      {
        public void componentShown(ComponentEvent e)
        {
          this_componentShown(e);
        }
      });
    this.addWindowListener(new java.awt.event.WindowAdapter()
      {
        public void windowClosing(WindowEvent e)
        {
          this_windowClosing(e);
        }
      });
    labFile.setLabelFor(tfFileName);
    labFile.setText("Enter a file name");
    bPickFile.setFocusable(false);
    bPickFile.setText("Choose file");
    bPickFile.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          bPickFile_actionPerformed(e);
        }
      });
    bExport.setText("Export");
    bExport.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          bExport_actionPerformed(e);
        }
      });
    bClose.setText("Close");
    bClose.addActionListener(new ActionListener()
      {
        public void actionPerformed(ActionEvent e)
        {
          bCancel_actionPerformed(e);
        }
      });
    labProgressCount.setText("Progress");
    labProgressTime.setText("Progress");
    labProgressSpeed.setText("Progress");
    pFile.setLayout(borderLayout1);
    pButtons.setLayout(gridBagLayout2);
    labCharset.setLabelFor(tfFileName);
    labCharset.setText("Charset");
    
    this.getContentPane().add(labFile,           new GridBagConstraints(0, 2, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(10, 13, 0, 10), 0, 0));
    this.getContentPane().add(tfFileName,        new GridBagConstraints(0, 3, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets( 3, 10, 3, 10), 0, 0));
    this.getContentPane().add(bPickFile,         new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE,       new Insets( 0, 10, 0, 10), 0, 0));
    this.getContentPane().add(labProgressCount,  new GridBagConstraints(0, 6, 2, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(10, 13, 0, 10), 0, 0));
    this.getContentPane().add(labProgressTime,   new GridBagConstraints(0, 7, 2, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 13, 0, 10), 0, 0));
    this.getContentPane().add(labProgressSpeed,  new GridBagConstraints(0, 8, 2, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets( 5, 13, 0, 10), 0, 0));
    this.getContentPane().add(pButtons,          new GridBagConstraints(0, 9, 2, 1, 0.0, 1.0, GridBagConstraints.SOUTH,     GridBagConstraints.BOTH,       new Insets( 0,  0, 0,  0), 0, 0));
    this.getContentPane().add(labCharset,        new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,    GridBagConstraints.NONE,       new Insets(10, 13, 0,  3), 0, 0));
    this.getContentPane().add(combCharset,       new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,    GridBagConstraints.HORIZONTAL, new Insets(10,  3, 3, 10), 0, 0));
    pButtons.add(bExport, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(10, 10, 10, 5), 0, 0));
    pButtons.add(bClose, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, new Insets(10, 5, 10, 10), 0, 0));
    pButtons.add(pCompensator, new GridBagConstraints(0, 0, 2, 1, 0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 10, 0, 10), 0, 0));
    
  } // jbInit

  private void bPickFile_actionPerformed(ActionEvent e) {
    JFileChooser chooser = new JFileChooser();
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);
    File typed = new File(tfFileName.getText());
    if(typed.isFile()) typed = typed.getParentFile();
    chooser.setCurrentDirectory(typed);
    if(chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
      tfFileName.setText(chooser.getSelectedFile().getAbsolutePath());
    }
  }

  private void bCancel_actionPerformed(ActionEvent e) {
    this_windowClosing(null);
  }
  //   
  private void bExport_actionPerformed(ActionEvent e) {
    if(inProgress) {
      stopProgress = true;
      bExport.setEnabled(false);
    } else {
      if(tfFileName.getText().length() < 1) {
        JOptionPane.showMessageDialog(this, General.getLangItem("FileNotChosen", 
          "File not chosen"), General.getLangItem("ErrorExcl", "Error!"), 
          JOptionPane.ERROR_MESSAGE); 
        tfFileName.requestFocusInWindow();
        return;
      }
      //
      File expFile = new File(tfFileName.getText());
      if(expFile.exists()) {
        if(expFile.isDirectory()) {
          JOptionPane.showMessageDialog(this, General.getLangItem("DirChosenFileNeeded", 
            "Directory is chosen while file needed."), General.getLangItem("ErrorExcl", "Error!"), 
            JOptionPane.ERROR_MESSAGE); 
          tfFileName.requestFocusInWindow();
          return;        
        }
        else if(expFile.isFile()) {
          int confirmResult = JOptionPane.showConfirmDialog(this, 
          General.getLangItem("WantToRewrite", "The file already exists. Rewrite?"),
          General.getLangItem("Question", "Question"), JOptionPane.YES_NO_OPTION); 
          if(confirmResult != JOptionPane.YES_OPTION) {
            tfFileName.requestFocusInWindow();
            return;        
          }
        }
      }
      //
      Thread t = new Thread("fulfilExport") {
        public void run() {
          fulfilExport();
        }
      }; 
      t.start();
    }
  }
  //
  private void indicateProgress(int count, int time) {
    int speed = time > 0 ? count / time : 0;
    int sec = time % 60; time /= 60;
    int min = time % 60; time /= 60;
    int hour = time;
    String res = Integer.toString(100 + hour).substring(1) + ":" +
                 Integer.toString(100 + min).substring(1) + ":" +
                 Integer.toString(100 + sec).substring(1);
    labProgressCount.setText(exportedCountLabel + ": " + Integer.toString(count));
    labProgressTime.setText(progressTimeLabel + ": " + res);
    if(speed > 0) labProgressSpeed.setText(progressSpeedLabel + ": " + Integer.toString(speed) + 
      " " + wordsPerSecond);
    else labProgressSpeed.setText(" ");
    //System.out.println(Integer.toString(count));
  }
  //
  /**
   * Придаем форме внешнее состояние "в процессе работы" или наоборот
   * @param inProgress в процессе или не в процессе
   */
  private void setStateInProgress(boolean inProgress) {
    labFile.setEnabled(!inProgress);
    tfFileName.setEnabled(!inProgress);
    bPickFile.setEnabled(!inProgress);
    bExport.setText(inProgress ? stopLabel : exportLabel);
    bClose.setEnabled(!inProgress);
    labCharset.setEnabled(!inProgress);
    combCharset.setEnabled(!inProgress);
  }
  /**
   * Собственно загрузка 
   */
  private void fulfilExport() {
    // Выбираем кодировку
    int cs = combCharset.getSelectedIndex();
    Charset сharset;
    if(cs < 0) сharset = Charset.forName(General.getDefaultCharset());
    else сharset = (Charset)charset.get(combCharset.getItemAt(cs));
    // Открываем файл 
    PrintWriter wordWriter;
    try {wordWriter = 
      new PrintWriter(
        new BufferedWriter(
          new OutputStreamWriter(
            new FileOutputStream(tfFileName.getText()), сharset
          )
        )
      );
    } catch (Exception ex) {
      ErrorShower.show(this, "opening file to export to", "", ex);
      return;
    } 
    
    // Preparing result set
    Statement st;
    ResultSet rs;
    try {    
      st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
        ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
      rs = st.executeQuery("select w.WORD from WORD w inner join " + 
        "DONE d on d.WORD_ID = w.ID and d.READER_CODE = user ");
    } catch (Exception ex) {
      ErrorShower.show(this, "preparing exporting result set", "", ex);
      return;
    }
    //
    setStateInProgress(true);
    //
    boolean stopNoticed = false; // обнаружена ли уже попытка прерывания процесса 
                                 // (чтобы точно определить, все ли слова загружены)
    inProgress = true;
    stopProgress = false;
    //
    indicateProgress(0, 0);
    // Начинаем выгрузку
    try {
      int wCount = 0;
      long beginWork = System.currentTimeMillis();
      int secondsLeft = 0;
      
      while (rs.next()) { 
        // Проверка прерывания 
        if(stopProgress) 
          if(stopNoticed) {
            JOptionPane.showMessageDialog(this, General.getLangItem("ExportStoppedByUser", 
              "Export prosess was interrupted by user.\nNot all the words exported."), 
              General.getLangItem("WarningExcl", "Warning!"), JOptionPane.WARNING_MESSAGE); 
            break;
          }
        else stopNoticed = true;
        // Выгрузка слова
        wordWriter.println(rs.getString(1));
        wCount++;
        //Thread.sleep(300);
        // Индикация хода работы 
        int newSecondsLeft = (int)(System.currentTimeMillis() - beginWork) / 1000;
        if(newSecondsLeft > secondsLeft) {
          secondsLeft = newSecondsLeft;
          indicateProgress(wCount, secondsLeft);
        }
      }
      //
      int newSecondsLeft = (int)(System.currentTimeMillis() - beginWork) / 1000;
      indicateProgress(wCount, newSecondsLeft);
      //  
    } catch (Exception ex) {
      ErrorShower.show(this, "exporting words", "", ex);
      //return;
    } finally {
      //
      try {
        wordWriter.close();
        rs.close();        
      } 
      catch (Exception ex) {ErrorShower.show(this, "closing export file and DB result set", "", ex);}
      //
      bExport.setEnabled(true);
      setStateInProgress(false);
      //
      inProgress = false;
    }
  }
  //
  private void this_windowClosing(WindowEvent e) {
    if(inProgress) JOptionPane.showMessageDialog(this, General.getLangItem("StopExportFirst", 
      "Please stop the export first"), General.getLangItem("ErrorExcl", "Error!"), 
      JOptionPane.ERROR_MESSAGE); 
    else {
      // Сохраняемся
      Properties prop = new Properties();
      prop.setProperty("LastFileName", tfFileName.getText());
      prop.setProperty("LastCharset", (String)combCharset.getSelectedItem());
      try {prop.store(new FileOutputStream("wfDialogExportMarked.properties"), 
        "DialogExportMarked parameters");} 
      catch (Exception ex) {ErrorShower.show(this, "saving the dialog properties", "", ex);}      
      // Закрываемся
      this.setVisible(false);
    }
  }

  private void this_componentShown(ComponentEvent e) {
    //System.out.println("=================================================");
    //System.out.println("CompensatorHeight=" + pCompensator.getHeight());
    //System.out.println("DialogHeight0=" + this.getHeight());
    this.setSize(this.getWidth(), this.getHeight() - pCompensator.getHeight() + 3);
    //System.out.println("DialogHeight1=" + this.getHeight());
    // Список кодировок 
    if(lastCharset == null || lastCharset.length() < 1) lastCharset = General.getDefaultCharset();
    Iterator it = charset.keySet().iterator();
    while (it.hasNext()) {
      String key = (String)it.next();
      combCharset.addItem(key);
      if(key.equals(lastCharset)) combCharset.setSelectedItem(key);
    }
    //// Список текстов 
    //try {General.fillTextList(combText, conn);} 
    //catch (Exception ex) {ErrorShower.show(this, "loading list of texts", "", ex);} 
  }

  /** Устанавливает язык интерфейса */
  public void setLang() {
    String s;
    s = General.getLangItem("ExportMarkedWords"); if(s.length() > 0) this.setTitle(s);
    s = General.getLangItem("EnterAFileName"); if(s.length() > 0) labFile.setText(s);
    s = General.getLangItem("ChooseFile"); if(s.length() > 0) bPickFile.setText(s);
    s = General.getLangItem("Export"); if(s.length() > 0) {exportLabel = s; bExport.setText(s);}
    s = General.getLangItem("Close"); if(s.length() > 0) bClose.setText(s);
    s = General.getLangItem("Charset"); if(s.length() > 0) labCharset.setText(s);
    s = General.getLangItem("exportedCountLabel"); if(s.length() > 0) exportedCountLabel = s;
    s = General.getLangItem("progressTimeLabel"); if(s.length() > 0) progressTimeLabel = s;
    s = General.getLangItem("progressSpeedLabel"); if(s.length() > 0) progressSpeedLabel = s;
    s = General.getLangItem("wordsPerSecond"); if(s.length() > 0) wordsPerSecond = s;
    s = General.getLangItem("stopLabel"); if(s.length() > 0) stopLabel = s;
  }
  
  


}